#============================================================
#   Skill 
#============================================================
# - datetime: 2022-06-23 15:48:37
#============================================================

## 技能节点
class_name Skill
extends Node


## 输入数据
signal inputted_data(data)

## 开始调用了技能
signal casted
## 执行准备（前摇动作）
signal execute_ready
## 执行前
signal execute_before
## 执行中
signal executing
## 执行后
signal execute_after
## 执行完成（后摇动作结束）
signal execute_ended

## 状态刷新了（冷却时间结束了）
signal refreshed
## 停止（调用 [method stop] 方法时发出这个信号）
signal stopped
## 中断（调用 [method interrupt] 方法中断成功时发出这个信号）
signal interrupted

## 倒计时开始
signal countdown_begin(time)


## 施法前摇时间
@export 
var before_shake_time : float = 0.0
## 持续时间
@export 
var duration_time : float = 0.0
## 施法后摇时间
@export 
var after_shake_time : float = 0.0
## 冷却时间
@export 
var cooldown : float = 0.0


## 技能计时器
class SkillTimer:
	var before_shake_timer : Timer = Timer.new()
	var after_shake_timer : Timer = Timer.new()
	var duration_timer : Timer = Timer.new()
	var cooldown_timer : Timer = Timer.new()
	
	func _init(host: Node):
		var timers = [before_shake_timer, after_shake_timer, duration_timer, cooldown_timer]
		for timer in timers:
			timer.process_callback = Timer.TIMER_PROCESS_PHYSICS
			timer.autostart = false
			timer.one_shot = true
			host.add_child.call_deferred(timer)


## 状态
class SkillState:
	enum {
		PRE_EXECUTE,	# 初始开始执行
		EXECUTE_READY,	# 准备执行
		EXECUTE_BEFORE,	# 执行前
		EXECUTING,		# 正在执行
		EXECUTE_AFTER,	# 执行后
		
		INTERRUPT,		# 打断施法
		COOLING,		# 冷却中
		REFRESHED,		# 已刷新
	}
	
	var current_state = REFRESHED
	
	## 是否可以施放
	func is_can_cast() -> bool:
		return current_state == REFRESHED or current_state == INTERRUPT
	
	## 是否正在执行中
	func is_executing() -> bool:
		return current_state == EXECUTING
	
	## 在执行阶段
	func is_in_execute_phase() -> bool:
		return current_state in [PRE_EXECUTE, EXECUTE_READY, EXECUTE_BEFORE, EXECUTING, EXECUTE_AFTER]
	
	## 执行阶段前
	func is_execute_phase_before() -> bool:
		return current_state in [PRE_EXECUTE, EXECUTE_READY, EXECUTE_BEFORE]
	
	##  执行阶段后
	func is_execute_phase_after() -> bool:
		return current_state in [EXECUTING, EXECUTE_AFTER]
	
	## 是否已被打断
	func is_interrupted() -> bool:
		return current_state == INTERRUPT
	
	## 停止执行
	func stop():
		# 已经执行了，则为“冷却中”的状态
		if current_state in [EXECUTING, EXECUTE_AFTER, INTERRUPT]:
			trans_to(COOLING)
		# 还未执行时停止了，则为刷新状态
		else:
			trans_to(REFRESHED)
	
	## 刷新
	func refresh():
		trans_to(REFRESHED)
	
	## 打断执行
	func interrupt():
		# 还未执行，则为打断
		if current_state in [EXECUTE_READY, EXECUTE_BEFORE]:
			trans_to(INTERRUPT)
		# 已经执行或执行过了，打断则切换为冷却状态
		elif current_state in [EXECUTING, EXECUTE_AFTER]:
			trans_to(COOLING)
	
	## 转换状态
	func trans_to(state):
		current_state = state


var _skill_timer : SkillTimer = SkillTimer.new(self)
var _skill_state : SkillState = SkillState.new()
var _force_timer : Timer = Timer.new()

var _input_data


#============================================================
#  Set/Get
#============================================================
## 技能是否可用
func is_enabled() -> bool:
	return (_skill_state.is_can_cast() 
		and _force_timer.time_left <= 0
	)

## 调用技能时传入的数据
func get_input_data():
	return _input_data

## 是否正在执行中
func is_executing() -> bool:
	return _skill_state.is_executing()

## 是否准备执行
func is_execute_phase_before() -> bool:
	return _skill_state.is_execute_phase_before()

##  获取技能的计时器
##[br]
##[br][code]return[/code]  返回计时器对象，里面包含有各个执行阶段 的计时器
func get_skill_timer() -> SkillTimer:
	return _skill_timer

##  获取冷却倒计时时间
##[br]
##[br][code]return[/code]  返回剩余时间
func get_cooldown_time_left() -> float:
	return _skill_timer.cooldown_timer.time_left


#============================================================
#   内置
#============================================================
func _ready():
	_skill_timer.before_shake_timer.timeout.connect(_execute_before)
	_skill_timer.duration_timer.timeout.connect(_execute_after)
	_skill_timer.after_shake_timer.timeout.connect(_execute_end)
	_skill_timer.cooldown_timer.timeout.connect(_refresh)
	
	_force_timer.one_shot = true
	_force_timer.autostart = false
	_force_timer.process_callback = Timer.TIMER_PROCESS_PHYSICS
	add_child(_force_timer)


#============================================================
#  自定义
#============================================================
##  执行技能 
##[br]
##[br][code]input_data[/code]  输入数据
##[br][code]return[/code]  返回是否执行成功
func run(input_data = null) -> bool:
	if is_enabled():
		_skill_state.trans_to(SkillState.PRE_EXECUTE)
		self._input_data = input_data
		inputted_data.emit(input_data)
		casted.emit()
		if not _skill_state.is_interrupted():
			_execute_ready()
			return true
	return false


## 准备
func _execute_ready():
	if not _skill_state.is_interrupted():
		_skill_state.trans_to(SkillState.EXECUTE_READY)
		execute_ready.emit()
		_force_timer.stop()
		if not _skill_state.is_interrupted():
			if before_shake_time > 0:
				_skill_timer.before_shake_timer.start(before_shake_time)
			else:
				_execute_before()


## 执行前
func _execute_before():
	if not _skill_state.is_interrupted():
		_skill_state.trans_to(SkillState.EXECUTE_BEFORE)
		execute_before.emit()
		_executing()


## 执行中
func _executing():
	if not _skill_state.is_interrupted():
		_skill_state.trans_to(SkillState.EXECUTING)
		executing.emit()
		if not _skill_state.is_interrupted():
			__pre_executing_after__()

func __pre_executing_after__():
	if duration_time > 0:
		_skill_timer.duration_timer.start.call_deferred(duration_time)
	else:
		_execute_after()


## 执行后
func _execute_after():
	_skill_state.trans_to(SkillState.EXECUTE_AFTER)
	execute_after.emit()
	if after_shake_time > 0:
		_skill_timer.after_shake_timer.start(after_shake_time)
	else:
		_execute_end()


## 执行完成
func _execute_end():
	_skill_state.trans_to(SkillState.COOLING)
	execute_ended.emit()
	if cooldown > 0:
		_skill_timer.cooldown_timer.start(cooldown)
		countdown_begin.emit(cooldown)
	else:
		_refresh()


## 功能刷新
func _refresh():
	_skill_state.refresh()
	refreshed.emit()


## 停止施放
func stop():
	if _skill_state.is_can_cast():
		return
	_skill_state.stop()
	stopped.emit()


## 打断施放
##[br]
##[br][code]immediate[/code]  立即打断（没有后摇动作）
##[br][code]force_cooldown[/code]  强制冷却倒计时时间
##[br]
##[br][code]return[/code]  返回打断是否成功
func interrupt(immediate = false, force_cooldown : float = 0.0) -> bool:
	if _skill_state.is_in_execute_phase():
		if immediate:
			# 还未开始执行实际功能时
			if _skill_state.is_execute_phase_before():
				_skill_timer.before_shake_timer.stop()
				if force_cooldown > 0:
					# 这里打断是正常执行时的打断，所以用 _skill_timer.cooldown_timer
					# 计时器，而不是 _force_timer 计时器，两个执行逻辑不一样
					_skill_timer.cooldown_timer.start(force_cooldown)
					countdown_begin.emit(force_cooldown)
			# 已经执行了实际功能时
			elif _skill_state.is_execute_phase_after():
				_execute_end()
		else:
			# 正在执行时，开始执行结束
			if _skill_state.is_executing():
				__pre_executing_after__()
		
		_skill_state.interrupt()
		interrupted.emit()
		return true
	else:
		return false
#		printerr("没有在执行阶段，打断技能无效")


##  强制进入冷却时间，这样技能就暂时不能使用了。
##[br]
##[br][code]time[/code]  倒计时时间
func force_countdown(time: float = 0.0) -> void:
	if time <= 0:
		time = cooldown
	_force_timer.start(max(0.001, time))
	countdown_begin.emit(time)
	

